package com.ruoyi.assemble.common.utils;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 对数拟合公式
 * 最小二乘法，拟合y=aln(x) + b
 *
 * @Author: sunzhijin
 * @Date: 2021/8/9 16:16
 */
public class LogFormula {
    private static final String POINT_DIGIT = "#.0000";

    public Map<String, Double> logFunction(List<List<Double>> data) {
        Map<String, Double> resultMap = new HashMap<>(2);
        DecimalFormat df = new DecimalFormat(POINT_DIGIT);
        Double xSum = 0.0;
        Double ySum = 0.0;
        Double xySum = 0.0;
        Double x2Sum = 0.0;
        int n = data.size();
        for (int i = 0; i < n; i++) {
            xSum = xSum + Math.log(data.get(i).get(0));
            x2Sum = x2Sum + Math.log(data.get(i).get(0)) * Math.log(data.get(i).get(0));
            xySum = xySum + data.get(i).get(1) * Math.log(data.get(i).get(0));
            ySum = ySum + data.get(i).get(1);
        }
        Double a = (xySum - ySum * xSum / n) / (x2Sum - xSum * xSum / n);
        Double b = (ySum - a * xSum) / n;
        resultMap.put("a", Double.parseDouble(df.format(a)));
        resultMap.put("b", Double.parseDouble(df.format(b)));
        return resultMap;
    }

    /**
     * @description: 获取预测结果
     * @author: FFP
     * @time: 2022/5/19 9:39
     */
    public List<List<Double>> getPowData(Double a, Double b, List<List<Double>> realData) {
        List<List<Double>> predictData = new ArrayList<>(realData.size());
        DecimalFormat df = new DecimalFormat(POINT_DIGIT);
        for (List<Double> data : realData) {
            List<Double> result = new ArrayList<>(2);
            if (data.get(0) == 0.0 && data.get(1) == 0.0) {
                continue;
            }
            result.add(data.get(0));
            if (data.get(0) == 0.0) {
                result.add(0.0);
            } else {
                Double y = Double.parseDouble(df.format(a * Math.log10(data.get(0)) + b));
                result.add(y);
            }
            predictData.add(result);
        }
        return predictData;
    }
}
